#coding: utf-8

require File.dirname(__FILE__) + '/web-socket-ruby-master/lib/web_socket'
require 'thread'


TAILLE_TAMPON     = 256
MESSAGE_SIZE      = 300
$logfile          = File.dirname(__FILE__) + "/log.log"
configfile        = File.dirname(__FILE__) + "/jip.conf"
$tab_socket         = {}
$tab_socket_inverse  = {}
$tab_dep          = {}
$tab_dep_inverse  = {}
$filesendingport  = "9876"
$mutex            = Mutex.new()

########################################################################
#  chargementInit(configfile): Chargement du fichier de config
#                              
#   MAJ des parametres: $port et $niveauDebugMax 
#   Par défaut : 
#      $port = "1978"
#      $logfile = "./log.log"
#      $niveauDebugMax = false  : signifie que les logs ne sont pas verbeux
########################################################################
def chargementInit(configfile)
  $port = 3007
  $niveauDebugMax = false
  tampon = nil
  File.open(configfile, File::RDONLY) do |fic|
    fic.each_line do|line|
    # log("INIT: #{line}")
      puts("INIT: #{line}")
      tmp = line.split("=",2)
      
      # $port = tmp[1].chomp.to_i if (tmp[0].upcase=="PORT")
      $filesendingport = tmp[1].chomp if (tmp[0].upcase=="FILESENDINGPORT")
      $logfile = tmp[1].chomp.delete "\"" if (tmp[0].upcase=="LOGFILE")     # le delete permet de supprimer les ""

      if (tmp[0].upcase=="DEBUG") 
        $niveauDebugMax = true if (tmp[1].chomp=="ON")
      end
    end
  end 
end

########################################################################
#  log(message,traceDebug=false): enregistre des traces
#                              
#   message est le message à afficher (précédé de la date et l'heure)
#   traceDebug active les traces "détails" si le niveau de débug Max est activé
########################################################################
def log(message,traceDebug=false)
  if ( $niveauDebugMax == false && traceDebug == true)
    # pas de logs car niveau de débug bas    
  else
    $mutex.lock
    $log.puts("[#{Time.now}] #{message}")
    puts("[#{Time.now}] #{message}")
    $mutex.unlock
  end
end

########################################################################
#  gestionMessage(buffer): gere les codes de message reçus
# 
#
#	IN:	buffer:message complet reçu du serveur (CODE_CMD + message(s))
#   RETURN: reponse    : la réponse formatée toTransmit

########################################################################
def gestionMessage(buffer, socket)
  log("****************************GESTION DES MESSAGES****************************",true)
  log("<== MESSAGE RECU: <#{buffer}>")
 
  # Création de la réponse
  tampon = buffer.split(" ",2)

    log("TYPE de MESSAGE #{tampon[0].upcase}",true) 
    case tampon[0].upcase
      when "/ID"
        log("Entre dans la boucle de ID",true)       
          if (tampon[1]!= nil)
            if (tampon[1].length >= MESSAGE_SIZE)
              reponse = "402" #message trop long
            else
			  $tab_socket[socket] = tampon[1]
			  $tab_socket_inverse[tampon[1]] = socket
              reponse = "200" # traitement cas nominal
            end
          else
            reponse = "404" # Erreur inconnue
          end


         
      when "/DEPENDANCES"
        log("Entre dans la boucle de DEPENDANCES",true)       
          if (tampon[1]!= nil)
            if (tampon[1].length >= MESSAGE_SIZE)
              reponse = "412" #message trop long
            else
      				idCalques = tampon[1].split(";")
      				if  ($tab_dep[$tab_socket[socket]] == nil)
      					$tab_dep[$tab_socket[socket]] = []
      				end

      				idCalques.each do |idC|
      					$tab_dep[$tab_socket[socket]] << idC
      					p $tab_dep
      					if  ($tab_dep_inverse[idC] == nil)
      						$tab_dep_inverse[idC] = []
      					end

					   $tab_dep_inverse[idC] << $tab_socket[socket]
				    end
				
              reponse = "210" # traitement cas nominal
            end
          else
            reponse = "414" # Erreur inconnue
          end
        
      when "/ANNOTATION"
        log("Entre dans la boucle de ANNOTATIONS",true)       
          if (tampon[1]!= nil)
            if (tampon[1].length >= MESSAGE_SIZE)
              reponse = "422" #message trop long
            else
			  idCalque = tampon[1]
              reponse = "220" # traitement cas nominal
			  list_Id = $tab_dep_inverse[idCalque]
			  list_Id.each do |id|
  				socket = $tab_socket_inverse[id]
  				socket.send("/UPDATE "+ idCalque)
			  end
            end
          else
            reponse = "424" # Erreur inconnue
          end
		  
      when "/QUIT"
        log("Entre dans la boucle de QUIT",true)       
		  reponse = "230" # traitement cas nominal
		  socket.close
		  id = $tab_socket[socket]
		  $tab_socket_inverse.delete(id)
		  $tab_socket.delete(socket)
		  
	  else
		  reponse = "000" # Erreur inconnue

		        
    end # case
    log("==> MESSAGE RENVOYE ")
    log(reponse)

  return reponse
end

########################################################################
#  Main
########################################################################      
begin
  chargementInit(configfile) 
  puts $logfile
  $log = File.open($logfile, "w")  

  log("****************************DEMARAGE DU SERVEUR****************************")
  log("port ==> #{$port} et niveauDebugMax ==> #{$niveauDebugMax}")
    
  # Vérification de la ligne de commande de l'appel
  raise "\nUsage: #{$0} [port]\n" if ARGV.length > 2 
  $port = ARGV[0] if (ARGV.length == 1)

  # Ouverture du port
  server = TCPServer.open($port)

  # Ouverture en ecriture du fichier log
  log("Lancement du serveur")

  # Mise en place d'un gestionnaire pour capturer SIGINT (CTRL + C)
  trap("SIGINT") do
      server.close
      server = nil   # pour le ensure
      log("Arrêt du serveur")
      $log.close
      exit 0
  end

  puts "en attente de la connexion d'un client..."
  
 
  server = WebSocketServer.new(:port => $port, :accepted_domains => ["*"])
  connections = []
  history = [nil] * 20
  server.run() do |ws|
	log("\n__________________________________________________________________")
		# The block is called for each connection.
		# Checks requested path    
		puts("Connection accepted")
		if ws.path == "/"
			puts("Ok")
			# Call ws.handshake() without argument first.
			ws.handshake()
			# Lance l'écoute
			while (message = ws.receive())
			 puts("Received: #{message}")
				reponse = gestionMessage(message, ws)
				ws.send(reponse)
			end
		else
		  # You can call ws.handshake() with argument to return error status.
		  ws.handshake("404 Not Found")
		end # case
  end


rescue Exception => e
  STDERR.puts e
  raise e
ensure
  server.close if server
  $log.close if $log and not $log.closed?
end